
"""
/*
 * Copyright 2011 OpenWAF.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
 """

from ConfigReader import WAFConfig
import sys
#from Analyzer import SGlobal





class Literal:
	DOUBLE	 = 1
	FLOAT	 = 2
	CHAR	 = 3
	STRING	 = 4
	INT	 = 5
	LONG	 = 6
	TRUE	 = 7
	FALSE	 = 8
	NULL	 = 9
	
	strings = {}
	index = 0
	
	
	MAX_INT = int("0x7FFFFFFF", 16)
	def __init__(self, t, value):
		self.typ = t
		self.value = value;
	def toJS(self):
		if self.typ == Literal.INT:
			if isinstance(self.value, str):data = self.value
			else:data = self.value.data
			if data.lower().startswith("0x"):
				value = int(data[2:], 16)
				if len(data[2:]) == 8 and int(data[2:3], 16) > 7:
					##http://stackoverflow.com/questions/319199/why-is-java-able-to-store-0xff000000-as-an-int
					value = value & Literal.MAX_INT
					value = value - 2147483648; 
				return str(value)
			else:
				return data
			
		if self.typ == Literal.DOUBLE:
			data = None
			if isinstance(self.value, str):data = self.value
			else:data = self.value.data
			if data[-1:].lower() == "d": return data[:-1]
			return data
		if self.typ == Literal.FLOAT:
			data = None
			if isinstance(self.value, str):data = self.value
			else:data = self.value.data
			if data[-1:].lower() == "f": return data[:-1]
			return data
		if self.typ == Literal.LONG:
			data = None
			if isinstance(self.value, str):data = self.value
			else:data = self.value.data
			if data[-1:].lower() == "l": return data[:-1]
			return data
		if self.typ == Literal.CHAR:
			if isinstance(self.value, str):data = self.value
			else: data = self.value.data
			if len(data) == 3: return str(ord(data[1]))
			data = data[1:-1]
			if len(data) == 2 and data[0] == "\\":
				if data == "\\n":return str(ord('\n'))
				if data == "\\b":return str(ord('\b'))
				if data == "\\f":return str(ord('\f'))
				if data == "\\t":return str(ord('\t'))
				if data == "\\r":return str(ord('\r'))
				return str(ord(data[1]))
			if data.lower().startswith("\u"):
				return str(int(data[2:], 16))
			else:
				print "Not handled ", data
				some_method()
				
			
		if self.typ == Literal.STRING:
			data = None
			if isinstance(self.value, str):
				data = self.value
			else:
				data = self.value.data
			if WAFConfig.isStringAggregateEnabled() == False:
				return data
			import Analyzer
			if Literal.strings.has_key(data):
				i = Literal.strings[data]
				if Analyzer.SGlobal.compiling_controller == True:
					return WAFConfig.getWAFRootObjectName() + ".$s[" + str(i) + "]"
				else:
					return WAFConfig.getWAFRootObjectName() + ".$[" + str(i) + "]"
			Literal.strings[data] = Literal.index
			
			if Analyzer.SGlobal.compiling_controller == True:
				data = WAFConfig.getWAFRootObjectName() + ".$s[" + str(Literal.index) + "]"
			else:
				data = WAFConfig.getWAFRootObjectName() + ".$[" + str(Literal.index) + "]"
			Literal.index += 1
			return data
			
				
		if self.typ == Literal.TRUE:return "true"
		if self.typ == Literal.FALSE:return "false"
		if self.typ == Literal.NULL:return "null"
	


class Modifier:
	PUBLIC		 = 1
	PROTECTED	 = 2
	PRIVATE		 = 3
	STATIC		 = 4
	ABSTRACT	 = 5
	FINAL		 = 6
	NATIVE		 = 7
	SYNCHRONIZED	 = 8
	TRANSIENT	 = 9
	VOLATILE	 = 10
	STRICTFP	 = 11



class PrimitiveType:
	BOOLEAN		 = 1
	BYTE		 = 2
	CHAR		 = 3
	SHORT		 = 4
	INT			 = 5
	LONG		 = 6
	FLOAT		 = 7
	DOUBLE		 = 8
	NULL		 = 9
	def __init__(self, value):
		self.value = value
	@staticmethod
	def toJ(value):
		if value==PrimitiveType.BOOLEAN: return "boolean"
		if value==PrimitiveType.BYTE: return "byte"
		if value==PrimitiveType.CHAR: return "char"
		if value==PrimitiveType.SHORT: return "short"
		if value==PrimitiveType.INT: return "int"
		if value==PrimitiveType.LONG: return "long"
		if value==PrimitiveType.FLOAT: return "float"
		if value==PrimitiveType.DOUBLE: return "double"		
class ClassOrInterfaceType:
	def __init__(self):
		self.fullname = None
		self.clazz = None
		self.names = None
		self.typeargs = None
		self.next = None

class Interface:
	def __init__(self):
		self.modifiers	 = None
		self.name	 = None
		self.package	 = None
		self.typepars	 = None
		self.extends	 = None
		self.body	 = None
class InterfaceField:
	def __init__(self):
		self.modifiers	 = None
		self.declarators = None
class InterfaceMethod:
	def __init__(self):
		self.modifiers	 = None
		self.typepars	 = None
		self.name	 = None
		self.pars	 = None
		self.throws	 = None
		self.rettyp	 = None
		self.stmts	 = None
		self.block = None
		self.is_void = False
		self.native_code = None

class Import:
	def __init__(self, names, isstar, isstatic):
		self.names = names
		self.isstar = isstar
		self.isstatic = isstatic

class Class:
	def __init__(self):
		self.modifiers	 = None
		self.package	 = None
		self.name	 = None
		self.typepars	 = None
		self.extends	 = None
		self.implements	 = None
		self.body	 = None

class TypeParameter:
	def __init__(self):
		self.name	 = None
		self.bound	 = None
		self.forclass = None
		self.formethod = None
		self.index	 = -1

class ClassBody:
	def __init__(self):
		self.decls	 = None
class StaticBlock:
	def __init__(self):
		self.block = None
		self.static = False
class Field:
	def __init__(self):
		self.modifiers	 = None
		self.declarators = None
class Method:
	def __init__(self):
		self.explconinv = None
		self.modifiers	 = None
		self.typepars	 = None
		self.name	 = None
		self.pars	 = None
		self.throws	 = None
		self.rettyp	 = None
		self.stmts	 = None
		self.block = None
		self.is_void = False
		self.native_code = None
		self.line_start=None
		self.offset_start=None
		self.line_end=None
		self.offset_end=None

class Type:
	
	def __init__(self):
		self.pm_type	 = None
		self.arraydim	 = None
		self.coit 		 = None
		self.bounds		 = None
		self.processed = False
	def isArray(self):
		from Analyzer import SGlobal
		if self.coit == None:return False
		return self.coit.clazz == SGlobal.arrayclass

	def isIterable(self):
		from Analyzer import SHelper
		if self.coit == None:return False
		clz = self.coit.clazz
		iterable = SHelper.getClassOnFullName("java.lang.Iterable")
		d = clz.getDegreeWithThis(iterable)
		return d != -1
		
	def getClass(self):
		from Analyzer import STypeDeclaration
		from Analyzer import SGlobal
		cls = self.coit.clazz
		if isinstance(cls, STypeDeclaration):
			return cls
		if isinstance(cls, TypeParameter):
			if cls.bound != None:
				if len(cls.bound) > 1:
					print "Mulitple Bound not suppoertd"
					sys.exit(0)
				return cls.bound[0].getClass()
		return SGlobal.objclass
	def getFieldWithThisAccess(self, name, only_static, accessing_class):
		from Analyzer import SHelper
		from Analyzer import ExField
		cls = self.getClass()
		if cls.inheritance_depth == None:cls.countInheritanceDepth()
		for depth in range(cls.inheritance_depth + 1):
			for f in cls.exmembers:
				if not isinstance(f, ExField):continue
				if f.level != depth:continue
				if f.field.name == name:
					if SHelper.canIAccessYou(f.field, accessing_class, only_static):
						return f
		print "Field not found"
		some_method()
	def mappAllPars(self, m, method_type_args, method):
		r = []
		cls = self.getClass()
		for p in m.pars:			
			r.append(cls.mapAndConvertType(p.typ, self.coit.typeargs, cls, method_type_args, method))
		return r
			
	def mapAndConvertType(self, type, method_type_args, method):		
		cls = self.getClass()
		return cls.mapAndConvertType(type, self.coit.typeargs, cls, method_type_args, method)
	def getMethodWithThisAccess(self, name, args, only_static, method_type_args, accessing_class):
		from Analyzer import SHelper
		from Analyzer import ExMethod
		cls = self.getClass()
		if cls.inheritance_depth == None:cls.countInheritanceDepth()
		_typeargs = self.coit.typeargs
		for depth in range(cls.inheritance_depth + 1):
			for m in cls.exmembers:
				if not isinstance(m, ExMethod):continue
				if m.level != depth:continue
				if m.method.name != name: continue						  
				if not SHelper.canIAccessYou(m.method, accessing_class, only_static):continue
				if len(m.pars) != len(args):continue
				pars = m.pars
				npars = []
				if cls.typepars != None and len(cls.typepars) > 0:					
					for p in pars:
						npars.append(cls.mapAndConvertType(p.typ, _typeargs, cls, None, None))
				else:
					for p in pars:
						npars.append(p.typ)
				if m.matchArgsModifiedPars(npars, args, _typeargs, cls, method_type_args):
					return m
		all_degrees = []
		for m in cls.exmembers:
			if not isinstance(m, ExMethod):continue
			if not m.method.name == name:continue
			if not SHelper.canIAccessYou(m.method, accessing_class, only_static):continue
			if len(m.pars) != len(args):continue
			pars = m.pars
			npars = []
			if cls.typepars != None and len(cls.typepars) > 0:
				for p in pars:
					npars.append(cls.mapAndConvertType(p.typ, _typeargs, cls, None, None))
			else:
				for p in pars:
					npars.append(p.typ)
			d = m.matchArgsAndGetDegreeModifiedPars(npars, args, _typeargs, cls, method_type_args)
			if d != None:
				all_degrees.append([d, m])
		no_of_methods = len(all_degrees)
		if no_of_methods == 0:
			import Analyzer
			m = Analyzer.SGlobal.objclass.getMethodWithThisAccess(name, args, only_static, method_type_args, accessing_class)
			if m != None:
				return m
			return None
		if no_of_methods == 1:return all_degrees[0][1]
		minda = []
		for i in range(len(args)):minda.append(-1)
		SHelper.getMinDegreeArray(all_degrees, 0, minda, len(args))
		mind_methods = []
		for i in range(0, no_of_methods):
			if SHelper.compareDegreeArray(all_degrees[i][0], minda, len(args)):
				m = all_degrees[i][1]
				mind_methods.append(all_degrees[i][1])
		if len(mind_methods) == 1:
			return mind_methods[0]
		min_level = 100000
		for m in mind_methods:
			if m.level < min_level:min_level = m.level
		final_methods = []
		for m in mind_methods:
			if m.level == min_level:
				final_methods.append(m)
		if len(final_methods) == 1:
			return final_methods[0]
		r = final_methods[0]
		print "Ambiguius method call", r.name
		return r 
		


class TypeArgument:
	def __init__(self):
		self.isany = False
		self.typ	 = None
		self.extends	 = None
		self.superclass	 = None
		self.ref		 = None #Ref to the type parameter in the class
class LocalVariableDeclaration:
	def __init__(self):
		self.modifiers = None
		self.vds = None


class VariableDeclarator:
	def __init__(self):
		self.name	 = None
		self.arraydim = 0 #just to hold it while reading not accessed later on
		self.init	 = None
		self.typ = None
		self.js_name = None
	def getJSName(self):
		return self.js_name

class ArrayInitializer:
	def __init__(self):
		self.part	 = None

class Parameter:
	def __init__(self):
		self.name = None
		self.modifier	 = None
		self.typ	 = None
		self.isellipsis = False
		self.js_name = None
	def getJSName(self):
		return self.js_name
class ExplicitConstructorInvocation:
	def __init__(self):
		self.primary = None
		self.nonWildcardTypeArguments = None
		self.isthis = None
		self.issuper = None
		self.arguments = None
class QualifiedName:
	def __init__(self):
		self.names = None

class Annotation:
	def __init__(self):
		self.name	 = None
		self.value	 = None
		self.valuepairs	 = None
	@staticmethod
	def isThere(ts):
		return ts.getCurrentToken().data == "@"
			#incomplete



class ElementValuePair:
	def __init__(self):
		self.name	 = None
		self.value	 = None

class Block:
	def __init__(self):
		self.stmts	 = None
class Stmt:
	def __init__(self):
		self.calls_model = False
	def callsModel(self):
		return self.calls_model
class StmtAssert(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.exp2 = None
		self.exp1 = None
class StmtExplicitConstructorInvocation(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.nw_typeargs = None
		self.is_this = False
		self.is_super = False
		self.arguments = None

class StmtLocalVariableDeclaration(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.lvd = None
##place holder for ; in case of empy block
class StmtSemicolon(Stmt):
	pass
class StmtBlock(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.block = None
class StmtExp(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.exp = None
class StmtIf(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.par_ex_calls_model = False
		self.par	 = None
		self.stmt_if	 = None
		self.stmt_else	 = None

class StmtFor(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.init	 = None
		self.cond	 = None
		self.exps	 = None
		self.stmt	 = None
class StmtForEach(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.vd = None  #usef in foreach  #deepakpatil84 this has been tweaked since there can associated with variable os it hold var
		self.exps	 = None
		self.stmt	 = None

class StmtDoWhile(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.stmt	 = None
		self.par	 = None

class StmtWhile(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.stmt	 = None
		self.par	 = None

class StmtTry(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.tryblock	 = None
		self.catches	 = None
		self.finallyblock = None

class StmtCatch(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.param	 = None
		self.block	 = None

class StmtSwitch(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.par	 = None
		self.cases	 = None

class StmtSwitchBlock(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.exp	 = None
		self.default	 = None
		self.stmts	 = None

class StmtSynch(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.par	 = None
		self.block	 = None

class StmtReturn(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.exp	 = None

class StmtThrow(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.exp	 = None

class StmtBreak(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.name	 = None

class StmtContinue(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.name	 = None

class StmtLabel(Stmt):
	def __init__(self):
		Stmt.__init__(self)
		self.name	 = None
		self.stmt	 = None

class Creator:
	def __init__(self):
		self.nwtypeargs	 = None
		self.typ	 = None
		self.ccr	 = None
		self.arraycreator = None
		self.processed = False
class CreatorArray:
	def __init__(self):
		self.name	 = None
		self.init	 = None
		self.arraydim	 = None
		self.exps	 = None
class CreatorInner:
	def __init__(self):
		self.nw_typeargs = None
		self.name = None
		self.typeargs	 = None
		self.arguments	 = None
		self.body	 = None


	

class OprAssign:
	NORMAL		 = 1
	PLUS		 = 2
	MINUS		 = 3
	MULTIPLY	 = 4
	DIVIDE		 = 5
	#SUBTRACT	=6 same as minus accidently got duplicated
	AND		 = 7
	OR		 = 8
	XOR		 = 9
	MOD	 = 10
	LEFT_SHIFT	 = 11
	RIGHT_SHIFT	 = 12
	RIGHT_RIGHT_SHIFT = 13

class OprBinary:
	AND	 = 14
	OR	 = 15
	XOR	 = 16

class OprLogical:
	AND	 = 17
	OR	 = 18

class OprRelational:
	GT	 = 19
	LT	 = 20
	GTE	 = 21
	LTE	 = 22

class OprEquality:
	ET	 = 23
	NET	 = 24

class OprShift:
	LEFT_SHIFT	 = 25
	RIGHT_SHIFT	 = 26
	RIGHT_RIGHT_SHIFT = 27

class OprTernary:
	IF	 = 28
	ELSE	 = 29

class OprAdditive:
	PLUS	 = 30
	MINUS	 = 31

class OprMultiplicative:
	MULTIPY	 = 32
	DIVIDE	 = 33
	MOD	 = 34

class OprUnary:
	INC	 = 35
	DEC	 = 36
	POSITIVE	 = 37
	NEGATIVE	 = 38
	NOT	 = 39
	TILDE	 = 40

class OprPostfix:
	INC	 = 41
	DEC	 = 42

class OprInstanceOf:#kind of confusing , just keep flow with other operators i.e. to categories
	INSTANCEOF = 43
class OprPrecedence:
	p = {}
	p[OprPostfix.INC] = [1, 0]
	p[OprPostfix.DEC] = [1, 0]
	
	p[OprUnary.INC] = [2, 1]
	p[OprUnary.DEC] = [2, 1]
	p[OprUnary.POSITIVE] = [2, 1]
	p[OprUnary.NEGATIVE] = [2, 1]
	p[OprUnary.NOT] = [2, 1]
	p[OprUnary.TILDE] = [2, 1]
	
	p[OprMultiplicative.DIVIDE] = [3, 0]
	p[OprMultiplicative.MOD] = [3, 0]
	p[OprMultiplicative.MULTIPY] = [3, 0]
	
	p[OprAdditive.PLUS] = [4, 0]
	p[OprAdditive.MINUS] = [4, 0]
	
	p[OprShift.LEFT_SHIFT] = [5, 0]
	p[OprShift.RIGHT_SHIFT] = [5, 0]
	p[OprShift.RIGHT_RIGHT_SHIFT] = [5, 0]
	
	p[OprRelational.GT] = [6, 0]
	p[OprRelational.GTE] = [6, 0]
	p[OprRelational.LT] = [6, 0]
	p[OprRelational.LTE] = [6, 0]
	
	p[OprEquality.ET] = [7, 0]
	p[OprEquality.NET] = [7, 0]
	
	p[OprBinary.AND] = [8, 0]
	p[OprBinary.XOR] = [9, 0]
	p[OprBinary.OR] = [10, 0]
	
	p[OprLogical.AND] = [11, 0]
	p[OprLogical.OR] = [12, 0]
	
	p[OprTernary.IF] = [13, 1]
	p[OprTernary.ELSE] = [13, 1]
	
	p[OprAssign.AND] = [14, 1]
	p[OprAssign.DIVIDE] = [14, 1]
	p[OprAssign.LEFT_SHIFT] = [14, 1]
	p[OprAssign.MINUS] = [14, 1]
	p[OprAssign.MOD] = [14, 1]
	p[OprAssign.MULTIPLY] = [14, 1]
	p[OprAssign.NORMAL] = [14, 1]
	p[OprAssign.NORMAL] = [14, 1]
	p[OprAssign.OR] = [14, 1]
	p[OprAssign.PLUS] = [14, 1]
	p[OprAssign.RIGHT_RIGHT_SHIFT] = [14, 1]
	p[OprAssign.RIGHT_SHIFT] = [14, 1]
	p[OprAssign.XOR] = [14, 1]	
	
class CompilationUnit:
	def __init__(self):
		self.filepath = None
		self.annotations	 = None
		self.package	 = None
		self.imports		 = []
		self.decl		 = []

#################
## Expressions
#################

class Expression():
	def __init__(self):
		self.parts = None
class ExPart:
	def __init__(self):
		pass

class ExPrimary(ExPart):
	def __init__(self):
		self.parts = None
class ExCreator:
	def __init__(self):
		self.creator = None
class ExType(ExPart):
	def __init__(self, typ):
		self.typ = typ
class ExOperator(ExPart):
	RIGHT_TO_LEFT = 1
	LEFT_TO_RIGHT = 0
	def __init__(self, value):
		self.value = value
	def getPrecedance(self):
		return OprPrecedence.p[self.value][0] 
	def isRightToLeft(self):
		return OprPrecedence.p[self.value][1] == 1
	def isLeftToRight(self):
		return OprPrecedence.p[self.value][1] == 0
		
	
class ExParExpression(ExPart):
	def __init__(self):
		self.exp = None
class ExIdentifier(ExPart):
	def __init__(self):
		self.name = None
class ExArrayIndex(ExPart):
	def __init__(self):
		self.exp = None

class ExArguments(ExPart):
	def __init__(self):
		self.arguments = None

class ExCastExpression(ExPart):
	def __init__(self):
		self.typ = None
		self.exp = None
class ExLiteral(ExPart):
	def __init__(self):
		self.literal = None
class ExArray(ExPart):
	def __init__(self):
		self.dimension = None
class ExTypeArguments(ExPart):
	def __init__(self):
		self.typeargs = None
class ExDot(ExPart):
	pass
class ExThis(ExPart):
	pass
class ExSuper(ExPart):
	pass
class ExClass(ExPart):
	pass
class ExVoid(ExPart):
	pass
class ExPrimitiveType(ExPart):
	def __init__(self):
		self.typ = None
class ExInnerCreator(ExPart):
	def __init__(self):
		self.creator = None
class InnerCreator:
	def __init__(self):
		self.nwtypeargs = None
		self.name = None
		self.typeargs = None
		self.classcreator = None
class ClassCreatorRest:
	def __init__(self):
		self.args = None
		self.body = None

###
## Enumeration Section
###

class Enum:
	def __init__(self):
		self.modifiers = None
		self.name = None
		self.implements = None
		self.body = None

class EnumBody:
	def __init__(self):
		self.constants = None
		self.decls = None #Array of classBodyDeclarations


class EnumConstant:
	def __init__(self):
		self.anno = None
		self.name = None
		self.args = None
		self.classbody = None






####
##Annotation type decls
###
class AnnotationType:
	def __init__(self):
		self.modifiers = None
		self.name = None
		self.body = None
		self.modifiers = None


class AnnotationMethod:
	def __init__(self):
		self.modifiers = None
		self.typ = None
		self.name = None
		self.elementvalue = None
